package plugin

import (
	"bufio"
	"errors"
	"gitee.com/injoyai/goutil/conv"
	"gitee.com/injoyai/goutil/crypt/tls"
	"gitee.com/injoyai/goutil/g"
	"gitee.com/injoyai/goutil/net/conn/v2"
	"gitee.com/injoyai/goutil/net/mqtt/v2"
	"gitee.com/injoyai/goutil/net/serial"
	"gitee.com/injoyai/goutil/net/tcp/v2"
	"gitee.com/injoyai/goutil/net/websocket"
	"gitee.com/injoyai/goutil/oss/io"
	"gitee.com/injoyai/goutil/oss/io/buf"
	"gitee.com/injoyai/goutil/protocol/rocketmq/v2"
)

type ConnectType string

const (

	/*
		数据通讯部分(步骤1),部分分包(步骤2) 枚举
		关注的是数据如何到达程序,
		并不在意是协议还是平台
		例如 AEP数据传输也可以HTTP,但是需要AEP相关配置,可以看做整体是个通讯协议(基于HTTP)
		例如 MQTT等底层都是TCP,实现了通讯(步骤1)和分包(步骤2)的过程,剩下就是解析(步骤3)
		例如 Websocket是基于HTTP实现的,也视作一个整体,关注的是分包后的数据

		Serial(串口),TCP,UDP,只是通讯(步骤1)


	*/

	/* 步骤1(通讯) */

	// Serial 串口
	Serial ConnectType = "Serial"

	// TCP 协议
	TCP ConnectType = "TCP"

	// UDP 协议(未实现)
	UDP ConnectType = "UDP"

	/* 步骤1(通讯) 和 步骤2(分包) */

	// AEP 电信IOT平台
	AEP ConnectType = "AEP"

	// OneNET 移动平台
	OneNET ConnectType = "OneNET"

	// HTTP 协议
	HTTP ConnectType = "HTTP"

	// MQTT 协议
	MQTT ConnectType = "MQTT"

	// Websocket 协议
	Websocket ConnectType = "Websocket"

	// RocketMQ 阿里云的tcp版本
	RocketMQ ConnectType = "RocketMQ"
)

type Connect struct {
	Type ConnectType `json:"type"` //通讯类型
	io.Writer
	io.MessageReader
	io.Closer
}

func NewConnect(Type ConnectType, cfg *conv.Map, f *buf.Frame) (*Connect, error) {
	writer, messageReader, closer, err := newConnect(Type, cfg, f)
	if err != nil {
		return nil, err
	}
	return &Connect{
		Type:          Type,
		Writer:        writer,
		MessageReader: messageReader,
		Closer:        closer,
	}, nil
}

func newConnect(Type ConnectType, cfg *conv.Map, f *buf.Frame) (writer io.Writer, messageReader io.MessageReader, closer io.Closer, err error) {

	defer g.Recover(&err)

	switch Type {
	case Serial:

		c, err := serial.New(&serial.Config{
			Address:  cfg.GetString("address"),
			BaudRate: cfg.GetInt("baudRate"),
			DataBits: cfg.GetInt("dataBits"),
			StopBits: cfg.GetInt("stopBits"),
			Parity:   cfg.GetString("parity"),
			Timeout:  cfg.GetDuration("timeout"),
		})
		g.PanicErr(err)

		client := NewFrame(bufio.NewReader(c), f)

		return c, client, c, nil

	case TCP:

		c, err := tcp.Dial(cfg.GetString("address"))
		g.PanicErr(err)

		reader := NewFrame(bufio.NewReader(c), f)
		return c, reader, c, nil

	case UDP:

		c, err := conn.DialUDP(cfg.GetString("address"))
		g.PanicErr(err)

		reader := NewFrame(bufio.NewReader(c), f)
		return c, reader, c, nil

	case AEP:

	case OneNET:

	case HTTP:

	case MQTT:

		c, err := mqtt.New(&mqtt.Config{
			BrokerURL: cfg.GetString("brokerURL"),
			ClientID:  cfg.GetString("clientID"),
			Qos:       cfg.GetUint8("qos"),
			Retained:  cfg.GetBool("retained"),
			Username:  cfg.GetString("username"),
			Password:  cfg.GetString("password"),
			Timeout:   cfg.GetDuration("timeout"),
			Debug:     cfg.GetBool("debug"),
			KeepAlive: cfg.GetDuration("keepAlive"),
			TLS:       false,
			TLSConfig: tls.Config{},
		})
		g.PanicErr(err)

		writer := io.PublisherToWriter(c, cfg.GetString("topic"))

		return writer, c, c, nil

	case Websocket:

		c, err := websocket.Dial(cfg.GetString("address"))
		g.PanicErr(err)

		return c, c.NewMessageReader(buf.ReadWithAll), c, nil

	case RocketMQ:

		pubCfg := &rocketmq.PublishConfig{
			Endpoint:   cfg.GetString("endpoint"),
			AccessKey:  cfg.GetString("accessKey"),
			SecretKey:  cfg.GetString("secretKey"),
			InstanceId: cfg.GetString("instanceId"),
			Topic:      cfg.GetString("topic"),
			Debug:      cfg.GetBool("debug"),
		}

		publish, err := rocketmq.NewPublisher(pubCfg)
		g.PanicErr(err)

		subscribe, err := rocketmq.NewSubscriber(&rocketmq.SubscribeConfig{
			PublishConfig: pubCfg,
			GroupID:       cfg.GetString("groupID"),
		})
		g.PanicErr(err)

		writer := io.PublisherToWriter(publish, cfg.GetString("topic"))

		closer := io.MultiCloser(publish, subscribe)

		return writer, subscribe, closer, nil

	}

	err = errors.New("暂不支持")

	return

}
